﻿unit UCommunicationJoinScreen;

interface

uses Types, SysUtils, Classes, Windows, ExtCtrls, Contnrs, UCommunication;

type
  TCommunicationJoinScreen = class(TUart)
  private
    function UnicodeToBuff(S: string; var buff: array of byte; Idx: Integer): Word;
  public
    procedure JoinScreenStr(s: String);
  end;

implementation

{ TCommunicationJoinScreen }
{$region '条屏控制协议V3.0.0_UNICODE版 接口说明书'}
(*******************  条屏控制协议V3.0.0_UNICODE版   *******************
  版本记录：(注，文档中灰色背景部分是修改前的原始内容)
  ┌────────────┬──────────┬─────────────────────────────────────────────────────
  │   日期	   │   版本  	│              说明
  │ 2010-02-24 │	V4.0.0	│1，增加对分区指令0x29的描述
  │ 2009-10-26 │	V3.0.0	│1，硬件设置中取消“减少字斜”。
  │            │          │2，信息属性中增加“速度级别”。
  │            │          │3，环绕边框增加1点或4点的选项完全配套的软件：V3.01.
  │            │          │   完全配套的固件：V2.27以上版本。
  │ 2009-06-01 │	V2.0.0	│文本信息修改为UNICODE格式，与2.0版控制卡兼容。
  │            │          │注意，从这个版本起，协议版本号采用和控制卡同步的方式。
  │            │          │即：当控制卡版本号为2.x.x时，和其匹配的协议也是2.x.x的。
  └────────────┴──────────┴─────────────────────────────────────────────────────
      关于UNICODE：从2009年5月份起，我们将逐渐停止旧版控制卡的销售，以后将全部转
  向全新的UNICODE增强型控制卡。（增强型控制卡解决诸多旧卡的问题，并升级了存储容
  量，而销售价格不变）
      如果您已经按照1.56版的协议开发好程序，那么将程序升级到能支持2.0控制卡，只
  需增加一个函数调用，十行代码即可完成。（具体代码见文尾）。
  ------------------------------------------------------------------------------
  通讯波特率：57600，8，N，1
  ------------------------------------------------------------------------------
  约定：
  1，如未特别说明，所有出现的数字（如：86、0x5A）均指二进制数字，而不是ASCII码。
  2，协议中所有长度大于8bit的数字，均以小端格式存储（低字节在前，高字节在后。）
  ------------------------------------------------------------------------------
第一部分：发送信息包总格式
    所有下发的指令信息包，都符合如下所述的指令格式：
  ------------------------------------------------------------------------------
    [16字节信息头部]+[32字节指令参数]+[指令扩展内容]+[4字节信息尾部]
  ------------------------------------------------------------------------------
信息头：
  ┌─────┬───────────────────────────────────────────────────────────────────────
  │字节 │  说明
  ├─────┼───────────────────────────────────────────────────────────────────────
  │0  	│ 信息头，固定 0xA0
  │1-2  │ 整个信息包长度，低字节在前，高字节在后。
  │3-4  │ 16bit屏ID，低字节在前，高字节在后，0x0000代表广播信息
  │5-8  │ 流水号低32位，作为指令的临时唯一标识，服务器端可以以此ID作为指令的唯一标识。
  │9-12 │ 流水号高32位，低字节在前，高字节在后。（该字段暂时保留）
  │13   │ 具体指令代码。详见第三部分具体描述。(在终端回馈包中，该字段用于表示错误代码)
  │14-15│ 保留，填充为0.
  │	  │ 指令参数：变长，至少32字节，少于32字节的用零填充到32字节。具体含义详见第三部分具体指令描述
  │	  │ 指令扩展内容：可选段，最多1024字节，如果发送的指令不需要展信息，则没有该段。
  └─────┴───────────────────────────────────────────────────────────────────────
  信息尾部：
  ┌─────┬───────────────────────────────────────────────────────────────────────
  │字节 │  说明
  ├─────┼───────────────────────────────────────────────────────────────────────
  │0-1  │ 16bit校验和，将本字节之前所有字节相加，取低16位。
  │2    │ 保留
  │3    │ 1字节信息结束标志，固定为 0x50
  └─────┴───────────────────────────────────────────────────────────────────────
  注，每条指令总长度不超过16+32+1024+4 = 1076字节，每条指令最短16+32+4 = 52字节。

第二部分，终端回馈信息包总格式
  所有回馈的信息包，均符合如下所述的格式：
  [终端回馈包格式和下行包格式相同，只是将包头标志改为“0xAF”，结束标志改为“0x5F”。
  执行结果通过“指令代码”字段返回。具体错误代码参照备注1.
  注1，	除非特别说明，否则回馈信息一般不超过52字节）
  注2，	对于群发信息，无论执行成功于否，终端都不会返回

第三部分，具体指令代码描述
  0x01 / 0x03、 发送信息指令： （注：0x01为历史遗留指令，已经废除）
  [信息头部(指令代码=0x03)] + [32字节选项块] +[信息内容]+[信息尾部]
信息头部：已在第一部分描述，以后不再列举。
选项块：
  ┌─────┬───────────────────────────────────────────────────────────────────────
  │字节 │  说明
  ├─────┼───────────────────────────────────────────────────────────────────────
  │0-1  │信息序号：低字节在前，高字节在后，从1开始，上限取决于控制板类型，信息的序号就是信息存放的位置。播放时将按照序号从小到大轮流播放。
  │2    │动画方式
	│    	│0x00-随机
	│    	│0x01-立刻显示
	│    	│0x02-左移，
	│    	│0x03-右移，
	│    	│0x04-上移
	│    	│0x05-下移，
	│    	│0x06-从左向右展开，
	│    	│0x07-从上向下展开，
	│    	│0x08-从中间向2边展开，
	│    	│0x09-水平百叶窗，
	│    	│0x0A-垂直百叶窗
	│    	│0x0B-上下交叉对进
	│    	│0x0C-左右交叉对展
	│    	│0x0D-连续左移（走马灯）
	│    	│0x0E-菱形扩散
	│    	│0x0F-斜向下移
	│    	│0x10-斜向左展
	│    	│0x11-马赛克
	│    	│0x12-下雨
  │3    │停留方式，低4位代表信息停留时是否闪烁0x0-不闪烁，0x1-亮灭闪，0x2-反白闪。
  │    	│【注：分区卡暂不支持停留闪】。高4位代表信息播放时是否伴随“环绕边框”，
  │    	│   bit4：是否有环绕边框(1=有，0=没有)；
  │    	│   bit5：4点环绕还是单点环绕（1=4点，0=单点）；
  │    	│   bit6：环绕速度（1=慢速，0=快速）。注意：只有单色屏支持4点的环绕边框。
  │    	│0x1-有环绕闪烁，0x0-无环绕闪烁
字节4：移动速度和级别，低4bit代表移动速度0x0-0xF，数字越大越快。高4bit代表速度级别，有效范围0x1-0xF数字越大越慢。
字节5：页面停留时间：0x00-0xFF，秒数。比如屏幕可以显示8个字，当前信息有16个字，那么前8个字移动完毕后，可以选择在屏幕上停留一会儿再显示后8个字。（注意，如果是位图信息，此字段的单位是1/4秒），如果为0xFF，则一直显示，不再切换到下一条信息。
字节6：闪烁间隔，有效范围0x02-0xFF，秒数。指“亮灭闪”或“反白闪”闪烁的间隔。间隔至少2秒。如果字节3停留方式=0，则该字段被忽略。只有停留时间大于2秒，闪烁效果才能出来。
字节7：连播次数，范围0x01-0xFF，0=1次、1=2次…，每条信息加载后，连续播放够指定的次数，才加载下一条信息。
字节8-15：起播时间段，格式：[日][月][年][0x00] [秒][分][时][0x00]，BCD码表示，如2008年2月15日13点20分10秒，字段内容为：0x15 0x02 0x08 0x00 0x10 0x20 0x13 0x00。(参考备注3)
字节16-23：停播时间段，格式同上。
字节24：文字颜色，bit0=红色开关；bit1=绿色开关；bit2=蓝色开关；（单色屏可直接填充为0x01，其中蓝色开关为保留字段，暂不支持）。
字节25：低4位代表内容类型，0x0代表文本，高4位代表播放方式，0x0代表普通信息
字节26：本信息处于分组中的序号.
字节27：本组信息总最大序号。（普通信息这2个字节直接填0）
字节28-29：“信息内容”的长度，低字节在前，高字节在后。
字节30：选项，bit7，代表本条信息播放前，是否先清屏（仅TF-3/TF-4支持），bit0-3，代表本条信息所在的分区。（注，该选项仅分区卡支持）
字节31：保留，填充为0。
	信息内容：
英文为ASCII码、汉字为内码，最长512个英文或者256个汉字。时间信息、温湿度、倒计时用特殊字符表示动态内容，位图信息或RTF信息为位图点阵，点阵获取采用从左到右，从上到下的顺序（先取第一行，再取最后一行。每行先取左边。8个点合成一个字节），如果是双色屏，绿色数据在红色之后。
文本信息均调用字库，内容就是文字的UNICODE编码。（需要对文字编码做处理，具体代码见文后）
    位图信息或RTF信息为位图点阵，点阵获取采用从左到右，从上到下的顺序（先取第一行，再取最后一行。每行先取左边。16个点合成一个WORD），如果是双色屏，绿色数据在红色之后。

注1：控制卡判断播放时间段时，将把日期和时间值分开判断，例如起播时间为2008-2-15 13:00:00，停播时间为2008-2-17 18:00:00。则本条信息将在2月15日至2月17日的13点到18点之间播放，而不是全天播放。当前时间大于等于起播时间时，并且小于停播时间时，信息处于可播放状态。
注2：如果开始结束日期年月日均为0，则代表不限日期。如果开始结束时间值均为0，则代表不限时间。如果日期、时间均为0，则本条信息在每次显示循环都会显示。
注3：如果停播小时值小于起播小时值，则代表跨子夜0点播放。
注4：控制卡上实际能存放的信息条数，在不同类型的卡上可能不同，取决于具体项目。
注5：如果信息序号相同，则后一条信息将覆盖前一条信息。

0x02、 追加信息内容
	[信息头部0x02] +[信息指令参数]+数据内容+[信息尾部]
如果要发送的信息内容超过1024字节，此时应先用指令0x03发送信息头部和信息前半部分内容，再循环调用本指令发送后续内容。
参数含义：
	指令参数：
字节0-1：主信息的序号，2字节
字节2-3，后续内容相对于整个信息内容的偏移量，低字节在前，高字节在后。
	数据内容：要追加的内容


0x05、 删除信息
[信息头部0x05] +[起始序号+结束序号]+[信息尾部]


0x06、 清除所有信息
	[信息头部0x06] +[信息尾部]
	清除类型：要清除的信息类型，
0x00代表删除所有信息，屏幕将只显示时间。（如果时间显示模式不为0）

0x08、 取消临时/报警信息
	[信息头部0x08]+ [参数]+[信息尾部]
发送取消报警指令后，如果当前屏幕正在显示报警信息或临时插播信息，则会取消该信息的显示。如果当前屏幕没有显示报警信息或临时插播信息，则没有效果。

0x09、 设定按键报警信息内容
	[信息头部0x09]+ [参数:是否开启按键报警]+[报警内容]+[信息尾部]
	参数：0代表不开启按键报警功能，1代表开启按键报警
报警内容将在报警键按下时在屏幕上显示，报报警内容不得超过16个字符（即8个汉字），少于16个字符时用空格补齐。
一旦进入报警状态，只有指令0x08或重启控制卡才能结束报警。
注意：该指令只适用于TF-20型控制卡

0x10、 设置显示屏亮度
[信息头部0x10]+[参数]+[信息尾部]
	参数：字节0代表亮度值：0x00-0x0F，共16级亮度，数字越大越亮


0x11、设置显示屏定时调亮度
[信息头部0x11]+[参数] +[信息尾部]
	参数：
一共6个时间段亮度部分，每个长2字节，结构如下
字节0：调节时间 0x00-0x23，BCD码表示的小时值。
字节1：亮度值0x00-0x0F，数字越大越亮
系统将在每条信息播放完成后检测当前时间和命令中的调节时间，到了调节时间的整点即会调节亮度。

0x12、设置显示屏自动调亮度
[信息头部0x12]+[参数]+ [信息尾部]
	如果设为显示屏自动调亮度，则控制卡将根据所处环境的光线强度自动调节显示屏亮度
注1：以上0x10-0x12实际为3种模式，即固定亮度值、按时间段调亮度、自动调亮度。控制卡同时只能处于一种亮度模式下。发送某个指令，即会指示控制卡切换到该指令代表的亮度模式。
注2：调节亮度功能和具体的控制卡类型有关，如果没有安装亮度传感器，发送0x12号指令将得到错误的执行结果。

0x13、读取亮度设置
[信息头部0x13]+[参数]+[信息尾部]
控制卡将在回馈信息的参数中，按照如下格式返回当前亮度设置
[当前亮度] [上次自动调节亮度的时间(小时值，仅在定时调亮度时有效)] [当前亮度调节方式(0x10-0x12)] [12字节定时亮度数据]

0x19，临时设置屏幕显示状态：(新指令，2.12版以后的控制卡才支持)
[信息头部0x19]+[参数]+[信息尾部]
	参数：显示状态，0x01-显示屏正常显示；0x00-黑屏（关机），不显示任何内容
    如果控制卡重启，则屏幕会恢复正常显示状态

0x20、设置屏幕显示状态
[信息头部0x20]+[参数]+[信息尾部]
	参数：显示状态，0x01-显示屏正常显示；0x00-黑屏（关机），不显示任何内容
   该指令发送的状态将保存，如果设置为黑屏，即使控制卡重启，重启后仍黑屏。

0x21、时间校正指令：
[信息头0x21]+[参数] +[信息尾]
	参数：
字节0-6：当前时间，年（00-99）、月、日、时、分、秒、周（0代表周日，1-6代表周一到周六）每个占1字节，均以BCD码表示。
字节7：时间显示模式，范围0x00-0x02，0代表不自动显示时间。1代表在没有任何信息时显示时间。2代表在每个显示循环开始自动插入时间显示。（注意：显示模式2已经废除）
字节8-9：16位时钟校正值，范围0-20000，10000代表不校正，小于10000代表加快时间，大于10000代表减慢时间。最大可校正1万点，每一点大约等于1/32768秒。
注1：时钟校正功能只有TF-3或TF-4型卡支持。

0x22、时间查询
[信息头0x22]+[参数]+[信息尾]
终端将在回馈信息参数字段中返回当前控制卡中的时间和时间显示格式，包结构为：[年][月][日][时][分][秒][周][显示格式]，每个占1字节，以BCD码表示。[16位校正值]（参照指令0x21）

0x23、显示屏硬件设置
[信息头部0x23]+[参数]+[信息尾部]

	参数：
字节0：显示屏宽度（单位：像素）/8
字节1：屏高（单位：像素）/8
字节2：颜色类型，1=普通；2=增强双色；3=彩色；（除分区卡外，其余卡不支持彩色）
字节3：数据极性，0=负极性；1=正极性
字节4：OE极性，0=负极性；1=正极性
字节5：行顺序，范围-15到+15
字节6：扫描类型，高4位表示扫描方式，低4位代表走线方式。（16分之一扫描可直接填充为0）
字节7：红绿互换，0=正常；1=显示时红绿互换（2008-11-27修订新增，仅用于预留暂不支持）
字节8：屏高数值的高8位，如果小于2048点，此处为0（目前暂时没有用到）
字节9：是否走字时减少字斜[3.0版已经废除]
字节10：数据镜像
字节11：扫描频率（预留.填充为0）
字节12：是否无138，1=无138，0=正常
字节13-15：预留，填充为0
注，显示屏实际宽高必须为8的整倍数，通常都为16的整倍数

typedef struct tagPanelData
{
	UI8 WidthModuleLow;	//屏宽/8
	UI8 HeightModule_;	//屏高/8
	UI8 ColorType;		//颜色类型
	UI8 DataPolar;		//数据极性
	UI8 OEPolar;			//oe极性
	I8	LineOffset;		//行顺序
	UI8 ScanType;		//扫描类型
	BOOL RGExchange;	//红绿互换
	UI8 WidthEx;
	UI8 ScanSpec;
	UI8 Mirror;
	UI8 ScanFreq;
	UI8 No138;
	UI8 Reserved[3];
}PanelData;

0x24、读取硬件设置
[信息头部0x24]+[参数]+[信息尾部]
控制卡将在回馈扩展信息中，按照上条命令的格式返回设置参数

0x25、设置控制卡（显示屏）ID
[信息头部0x25]+[参数：新ID]+[信息尾部]
	新ID：2字节，低字节在前，高字节在后，指令返回后将立刻生效。本条指令仍用旧ID返回


0x26、设置控制卡自动开关机
[信息头部0x26]+[参数：自动开关机模式+开机时+开机分+关机时+关机分]+[信息尾部]
	自动开关机模式：0x0=不自动开关机；0x01=每天自动开关机；0x02=除周末外每天自动开关机
	开机时：自动开机小时值，范围0x00-0x23,BCD码表示
	开机分：自动开机分钟值，范围0x00-0x59,BCD码表示
	关机时：自动关机小时值，范围0x00-0x23,BCD码表示
	关机分：自动关机分钟值，范围0x00-0x59,BCD码表示

0x27、读取屏幕开关机设定
[信息头部0x27]+[参数]+[信息尾部]
控制卡将在回馈信息参数中，按照如下格式返回参数内容：
[当前显示状态(0=黑屏;1=亮屏)][自动开关机模式] [开机时] [开机分] [关机时] [关机分]

0x28、设置默认波特率
[信息头部0x28]+[参数:4字节波特率]+[信息尾部]
	新波特率：只接受9600、19200、38400、57600、115200，发送其余数字将造成控制卡失去控制。
返回时仍用旧波特率发送。

	提示，修改波特率后，发送恢复出厂设置指令时，波特率不会恢复。

0x29、设置分区信息
[信息头部0x29]+[32字节参数]+[信息尾部]
	参数共32字节，由4个如下所述的结构组成，每个结构设置一个分区，最多可开启4个分区。

typedef struct tagZoneData
{
	UI8 Enable;				//本分区是否开启，1=开启；0=不开启
	UI8 Left; 				//分区的水平起始位置/8。（整个屏幕的左上脚为原点）
	UI8 Top;					//分区的垂直起始位置/8。
	UI8 Width;				//分区的宽度/8
	UI8 Height; 				//分区的高度/8
	UI8 Reserved[3];			//保留字节，填充为0
}ZoneData;
注意：各个分区之间不可重叠，分区大小不可超过屏幕总大小，否则将出现无法预料的后果（如：损坏控制卡）。
分区的位置、大小，最好是16的整数倍。
如果分区不开启，则位置和大小参数将忽略，即不开启的分区可以直接全部填充为0.

0x30、测试指令
[信息头部0x30]+[参数]+[信息尾部]
	本信息用于内部测试控制卡通讯是否正常，通常控制卡将把参数内容复制返回。此指令没有任何实际效果。

0x31、校验和字段是否有效开关
[信息头部0x31]+[参数：1字节开关]+[信息尾部]
	校验开关：0x01-终端收到数据包后将正常检查校验和字段。0x00-忽略校验和字段。

在测试初期，为了方便测试，可以通过该命令关闭校验和检查功能。协议调通后再打开该字段。
注意，此指令仅用在测试期间，在显示屏正式使用时请勿发送该指令，在最终用户的软件界面中亦不要出现该指令。即使设置为不检查校验和，控制卡每次开机也会自动恢复到校验状态。


0x32、控制卡重启
[信息头部0x32]+[参数]+ [信息尾部]
命令效果：控制卡重启，类似关电重开的效果

0x33、参数复位
[信息头部0x33]+[参数]+ [信息尾部]
命令效果：所有用软件设置的参数将恢复出厂设置。（包括屏参、亮度、开关机参数等，不会恢复默认波特率）

0x35、获取控制卡固件版本
[信息头部0x35]+[参数]+ [信息尾部]
控制卡将在回馈信息参数中返回固件版本，格式为：[控制卡类型][固件主版本][固件次版本] [修订版本][存储代码]


0x40、查询控制卡信息
[信息头部0x40]+[参数]+ [信息尾部]
本指令用于无线系统中获取控制卡ID，下发时请将信息头部的控制卡ID设置为0，控制卡会回复本信息，并且信息头部包含正确的控制卡ID。
    注意：1，除了本指令，其余指令将信息头部的控制卡ID设置为0将被认为是广播指令，不会收到返回包。）
          2，如果处于485联网状态，请不要发送该信息，否则会冲突！


第四部分，备注内容
1，为了保持终端对服务器的响应速度，通常终端不会对服务器的包做太多校验，终端返回的错误含义为：
1.1	收到的包格式正确，但是校验和验证错误。错误码为 1。（如果收到的包格式不正确，终端会丢弃该包，不会发出回馈信息）
1.2	收到的包验证正确，但是指令无法识别。错误码为2.
1.3	收到的包验证正确，但是指令尚未实现或者控制卡不支持。错误码为3.
1.4	包中参数错误，如发送信息时指定的ID大于控制卡允许的ID上限、设置硬件参数时指定的屏幕高宽超出最大范围。错误码为4.
1.5	单片机检测到包内容错误，比如包长度不足或内容不符合基本规则等。错误码为5
1.6	指令执行失败，如写入ROM再读出校验错误、报警状态发送了普通指令等。错误代码为6
返回0代表执行成功。

2，协议支持的信息ID最大值为0xFFFF，但是控制卡型号不同，支持的信息数量不同。

3，由于终端中的时间可能存在误差，并且由于信息是轮流演示，如果设置信息的显示时间过短，可能信息无法得到显示。尽量将信息的显示时间段精确到分钟，而不是秒。

5，如果有多条指令要发送，服务器应在收到上条指令回应后再发送下条指令，并且在连续发送的指令间增加10ms以上的延时，否则控制卡可能因无法及时处理所收到的信息而丢包。

6，如果发送信息没有收到回应，一段时间后可认为超时，可尝试重新发送。超时时间根据网络环境而定，如果采用GPRS方式，应等待至少1分钟才可判定超时。如果采用串口线短距离传输，超时时间可设为200ms - 数秒。

7，协议中所有出现时间的地方，时间中的“小时”值只接受24小时制，如果传入12小时制，可能会得到错误的结果。

第五部分，UNICODE编码详细说明

   1， 2.0版以前的控制卡，发送文本信息时，采用ANSI编码（ASCII码）。如“啊”字，其内码是“0xB0 0xA1”，字母‘A’的ASCII码是“0x41”。 汉字占用2字节，英文字母占用1字节。

   2，2.0版以后的控制卡，发送文本信息时，发送处理过的UNICODE编码， UNICODE编码无论英文或汉字，均以16bit表示（即占2字节）。如“啊”字的UNICODE编码是“0x4A 0x55”， 字母“A”的UNICODE编码是“0x41 0x00”。

    3，UNICODE和ANSI编码的区别。
UNICODE以16bit代表一个字符，英文字符和ANSI编码兼容。如字母“A”，在ANSI编码中是0x41，在UNICODE中是0x41 0x00， 转换为一个16bit的数字后，是0x0041。
汉字和世界上其它地方的语言，采用统一的编码。（在我们新板卡中，字库已经包含了所有的汉字（简体、繁体、生僻字），但不包括其它国家的文字，如韩文等）

4，如何获取汉字的UNICODE编码
以VC6语言为例，定义一个默认ANSI字符串的代码是：
LPCSTR lpText = “LED显示屏”;
此时可以通过指针lpText，逐一获取该段文字的ANSI编码。其结果为：“4C 45 44 CF D4 CA BE C6 C1”。

而定义一个UNICODE字符串的代码是：
LPCWSTR lpText = L” LED显示屏”;
	此时，通过lpText就可以获取该段文字的UNICODE编码，只不过现在的lpText指向的是一个16bit的缓冲区，要以WORD的方式获取。其结果为：“004C 0045 0044 663E 793A 5C4F”。 表示为byte数组，就是：“4C 00 45 00 44 00 3E 66 3A 79 4F 5C”。

5，发送文字的UNICODE编码时，要做什么处理
控制卡在接收文字时，并不是原封不动的接收其UNICODE编码，而是要做一定的处理，以便于控制卡显示。具体处理代码为：
（其中lpStr是要转换的原始UNICODE字符串，pBuff是用于存放转换结果的缓冲区）
void CopyWchar(LPCWSTR lpStr, WORD *pBuff)
{
	int nCount, nLen = 0;
	nCount = wcslen(lpStr);
	WCHAR ch;
	for(int i=0; i<nCount; i++)
	{
		ch = lpStr[i];
		if(ch >= 0x80)
		{
			if(ch <= 0xFF)
				ch -= 0x80;
			else if(ch >= 0x2000 && ch <= 0x266F)
				ch = ch - 0x2000 + 128;
			else if(ch >= 0x3000 && ch <= 0x33FF)
				ch = ch - 0x3000 + 1648 + 128;
			else if(ch >= 0x4E00 && ch <= 0x9FA5)
				ch = ch - 0x4E00 + 1648 + 1024 + 128;
			else if(ch >= 0xF900 && ch <= 0xFFFF)
				ch = ch - 0xF900 + 1648 + 1024 + 20902 + 128;
			ch += 128;
		}
		pBuff[i] = ch;
	}
}

6，通过Windows自带的“记事本”程序，即可方便的获得文字的ANSI编码或UNICODE编码，通过“文件”->“另存为”，打开保存界面，即可指定编码格式。再用UE打开保存的文本文件，就可获得具体编码。 （注：记事本程序为了识别，如果保存为UNICODE编码格式，记事本程序会自动在文件开头添加0xFF 0xFE这2个字节，请忽略）


第六部分，示例包
注：示例包仅作参考，因为版本升级的原因大部分已经过时。

1，发送文本信息 “LED显示屏”，进入动画=“立刻显示”，停留时间=“2”，颜色=“红”：
A0 40 00 01 00 04 00 00 00 00 00 00 00 03 00 00 01 00 01 00 0E 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 0C 00 00 00 4C 00 45 00 44 00 AE 23 AA 36 BF 19 67 04 00 50

2，发送文本信息“我爱我家”，进入动画=“连续左移”，停留时间=“0”，颜色=“黄”，环绕边框=“开”
A0 3C 00 01 00 05 00 00 00 00 00 00 00 03 00 00 01 00 0D 10 0E 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 08 00 00 00 81 1F A1 2F 81 1F 26 19 6D 03 00 50

3，发送时间信息“今天是20xx年xx月xx日 星期xx，现在时间xx时xx分。”：
A0 70 00 01 00 06 00 00 00 00 00 00 00 03 00 00 02 00 01 00 0E 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 05 00 00 3C 00 00 00 3A 0C 99 16 9F 23 32 00 30 00 0B 00 0C 00 E4 1B 0D 00 0E 00 78 24 0F 00 10 00 55 23 20 00 8F 23 8F 24 15 00 22 63 20 31 98 14 66 23 64 53 11 00 12 00 66 23 13 00 14 00 76 0F 72 07 1B 0C 00 50

4，设置显示屏亮度为手动模式，亮度值=14：
A0 34 00 01 00 07 00 00 00 00 00 00 00 10 00 00 0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FA 00 00 50

5，发送RTF信息，信息ID=3，播放动画=“上移”，停留时间=“6”，停留闪烁=“亮灭闪”，闪烁间隔=“2”
注意，屏参必须是32点*64点双色，才能正确看到内容，内容是“欢迎光临 Welcome”

A0 34 02 01 00 10 00 00 00 00 00 00 00 03 00 00 03 00 04 01 0E 06 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 10 02 01 10 00 00 7D 01 6F 22 21 10 00 00 09 F0 49 12 45 3F 00 00 4A 16 49 0A 85 28 00 00 2A A2 49 7F F5 44 00 00 10 82 49 09 05 00 00 00 10 82 79 09 05 3F 00 00 29 42 4B 09 05 29 00 00 25 42 08 09 15 29 00 00 42 25 80 11 11 3F 00 00 0C 14 7F 60 F1 21 00 00 00 00 00 00 00 00 00 00 42 10 10 00 00 00 00 00 45 10 10 00 00 00 00 00 45 23 93 0E 59 8E 00 00 25 24 54 91 66 51 00 00 28 A4 54 11 44 51 00 00 28 A7 D4 11 44 5F 00 00 28 A4 14 11 44 50 00 00 10 44 54 91 44 51 00 00 10 43 93 0E 44 4E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 10 10 00 00 00 00 00 45 10 10 00 00 00 00 00 45 23 93 0E 59 8E 00 00 25 24 54 91 66 51 00 00 28 A4 54 11 44 51 00 00 28 A7 D4 11 44 5F 00 00 28 A4 14 11 44 50 00 00 10 44 54 91 44 51 00 00 10 43 93 0E 44 4E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D8 2A 00 50

6，删除第三条信息：
A0 34 00 01 00 11 00 00 00 00 00 00 00 05 00 00 03 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F1 00 00 50

7，清除屏内的所有信息：
A0 34 00 01 00 12 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ED 00 00 50

8，硬件设置：
A0 34 00 01 00 15 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 00 00 50

*)
{$endregion}
procedure TCommunicationJoinScreen.JoinScreenStr(s: String);
var
  Data: array[0..655]of byte;
  FScreenComm: TUart;
  l, crc: Word;
  I: Integer;
begin
  l:= UnicodeToBuff(s, Data, 48);
  Data[00]:= $A0; //信息头，固定 0xA0
  crc:= l + 16 + 32 + 4;
  Move(crc, Data[01], 2); //字节1-2：整个信息包长度，低字节在前，高字节在后。
  Data[03]:= $01; Data[04]:= $00; //字节3-4： 16bit屏ID，低字节在前，高字节在后，0x0000代表广播信息
  Data[05]:= $05; Data[06]:= $00; Data[07]:= $00; Data[08]:= $00; //字节5-8： 流水号低32位，作为指令的临时唯一标识，服务器端可以以此ID作为指令的唯一标识。
  Data[19]:= $00; Data[10]:= $00; Data[11]:= $00; Data[12]:= $00; //字节9-12：流水号高32位，低字节在前，高字节在后。（该字段暂时保留）
  Data[13]:= $03; //字节13：具体指令代码。详见第三部分具体描述。(在终端回馈包中，该字段用于表示错误代码)
  Data[14]:= $00; Data[15]:= $00; //字节14-15：保留，填充为0
  // 指令参数：变长，至少32字节，少于32字节的用零填充到32字节。具体含义详见第三部分具体指令描述
  Data[16]:= $01; Data[17]:= $00; //字节0-1：信息序号：低字节在前，高字节在后，从1开始，上限取决于控制板类型，信息的序号就是信息存放的位置。播放时将按照序号从小到大轮流播放。
  Data[18]:= $0D; //字节2：动画方式    0x0D-连续左移（走马灯）
  //字节3：停留方式 0000 0000
  //                  │    └──────低4位代表信息停留时是否闪烁0x0-不闪烁，0x1-亮灭闪，0x2-反白闪。
  //                  └───────────高4位代表信息播放时是否伴随“环绕边框”，bit4：是否有环绕边框(1=有，0=没有)；bit5：4点环绕还是单点环绕（1=4点，0=单点）；bit6：环绕速度（1=慢速，0=快速）。
  Data[29]:= $10;
  Data[20]:= $74; //字节4：移动速度和级别，低4bit代表移动速度0x0-0xF，数字越大越快。高4bit代表速度级别，有效范围0x1-0xF数字越大越慢。
  Data[21]:= $00; //字节5：页面停留时间
  Data[22]:= $02; //字节6：闪烁间隔，有效范围0x02-0xFF，秒数
  Data[23]:= $00; //字节7：连播次数，范围0x01-0xFF
  //字节8-15：起播时间段
  Data[24]:= $00; Data[25]:= $00; Data[26]:= $00; Data[27]:= $00;
  Data[28]:= $00; Data[29]:= $00; Data[30]:= $00; Data[31]:= $00;
  //字节16-23：停播时间段
  Data[32]:= $00; Data[33]:= $00; Data[34]:= $00; Data[35]:= $00;
  Data[36]:= $00; Data[37]:= $00; Data[38]:= $00; Data[39]:= $00;
  Data[40]:= $03; //字节24：文字颜色，bit0=红色开关；bit1=绿色开关；bit2=蓝色开关；
  Data[41]:= $00; //字节25：低4位代表内容类型，0x0代表文本，高4位代表播放方式，0x0代表普通信息
  Data[42]:= $00; //字节26：本信息处于分组中的序号
  Data[43]:= $00; //字节27：本组信息总最大序号。（普通信息这2个字节直接填0）
  Move(l, Data[44], 2);
  //Data[44]:= $08; Data[45]:= $00; //字节28-29：“信息内容”的长度，低字节在前，高字节在后。
  Data[46]:= $00; //字节30：选项，bit7，代表本条信息播放前，是否先清屏（仅TF-3/TF-4支持），bit0-3，代表本条信息所在的分区。（注，该选项仅分区卡支持）
  Data[47]:= $00; //字节31：保留，填充为0
  //Move(strData[0], Data[48], l);
  crc:= 0;
  for I:= 0 to 47 + l do crc:= crc + Data[I];
  Move(crc, Data[48 + l], 2);
  Data[48 + l + 2]:= $00;
  Data[48 + l + 3]:= $50;
  Send(Data, 48 + l + 4);
end;

function TCommunicationJoinScreen.UnicodeToBuff(S: string;
  var buff: array of byte; Idx: Integer): Word;
type
  WC = packed record
    case integer of
    0: (c: char);
    1: (w: word);
    2: (b: array[0..1]of byte);
    end;
var
  strData: TBytes;
  ch: WC;
  i, nCount: Integer;
begin
  nCount:= Length(S);
  Result:= 0;
  for I := 1 to nCount do begin
    ch.c:= S[I];
		if ch.w >= $80 then begin
			if ch.w <= $FF then
				ch.w := ch.w - $80
			else if(ch.w >= $2000)and(ch.w <= $266F) then
				ch.w := ch.w - $2000 + 128
			else if(ch.w >= $3000)and(ch.w <= $33FF) then
				ch.w := ch.w - $3000 + 1648 + 128
			else if(ch.w >= $4E00)and(ch.w <= $9FA5) then
				ch.w := ch.w - $4E00 + 1648 + 1024 + 128
			else if(ch.w >= $F900)and(ch.w <= $FFFF) then
				ch.w := ch.w - $F900 + 1648 + 1024 + 20902 + 128;
			ch.w := ch.w + 128;
    end;
    buff[Idx]:= ch.b[0];
    buff[Idx + 1]:= ch.b[1];
    Inc(Idx, 2);
    Inc(Result, 2);
  end;
end;

end.
